#pragma once
#include "base/core/com_define.h"
using namespace luabridge;

template <class T>
bool LuaScript::PushObj(T t) 
{
    luabridge::push<T>(lua_state_, t);
    return true;
}

template <class T>
bool LuaScript::SetGlobal(const char* name, T t) 
{
    luabridge::setGlobal<T>(lua_state_, t, name);
    return true;
}

template<typename... PARAM>
bool LuaScript::CallFuncVoid(const char* func, PARAM... params) 
{
    BeginScriptProfilerTimer("", func);
    MMO_ASSERT(func);
    MMO_ASSERT(lua_state_);

    bool result = false;
    try 
	{
        LuaRef ref = luabridge::getGlobal(lua_state_, func);
        MMOLOG_ASSERT_EXIT(ref.isFunction());
        ref(params...);
    }
    catch (luabridge::LuaException& err) 
	{
        OutputError(func, err);
        goto Exit0;
    }
    result = true;
Exit0:
    EndScriptProfilerTimer();
    return result;
}

template<typename RETURN, typename... PARAM>
bool  LuaScript::CallFuncRet(const char * func, RETURN & retValue, PARAM... params) 
{
    BeginScriptProfilerTimer("", func);
    MMO_ASSERT(func);
    MMO_ASSERT(lua_state_);

    bool result = false;
    try 
	{
        LuaRef ref = luabridge::getGlobal(lua_state_, func);
        MMOLOG_ASSERT_EXIT(ref.isFunction());
        LuaRef ret = ref(params...);
        retValue = ret.cast<RETURN>();
    }
    catch (luabridge::LuaException& err) 
	{
        OutputError(func, err);
        goto Exit0;
    }
    result = true;
Exit0:
    EndScriptProfilerTimer();
    return result;
}

template<typename... PARAM>
bool  LuaScript::CallTableFuncVoid(const char* table, const char* func, PARAM... params) 
{
    BeginScriptProfilerTimer(table, func);
    MMO_ASSERT(table);
    MMO_ASSERT(func);
    MMO_ASSERT(lua_state_);
    bool result = false;
    try 
	{
        LuaRef ref = luabridge::getGlobal(lua_state_, table);
        MMOLOG_ASSERT_EXIT(ref.isTable()); // ������ASSERT
        {
            LuaRef fun = ref[func];
            MMOLOG_ASSERT_EXIT(fun.isFunction());
            fun(ref, params...);
        }
    }
    catch (luabridge::LuaException& err) 
	{
        OutputError(table, func, err);
        goto Exit0;
    }
    result = true;
Exit0:
    EndScriptProfilerTimer();
    return result;
}

template<typename RETURN, typename... PARAM>
bool  LuaScript::CallTableFuncRet(const char * table, const char * func, RETURN & retValue, PARAM... params) 
{
    BeginScriptProfilerTimer(table, func);
    MMO_ASSERT(table);
    MMO_ASSERT(func);
    MMO_ASSERT(lua_state_);

    bool result = false;
    try 
	{
        LuaRef ref = luabridge::getGlobal(lua_state_, table);
        MMOLOG_ASSERT_EXIT(ref.isTable());
        {
            LuaRef fun = ref[func];
            MMOLOG_ASSERT_EXIT(fun.isFunction());
            {
                LuaRef ret = fun(ref, params...);
                retValue = ret.cast<RETURN>();
            }
        }
    }
    catch (luabridge::LuaException& err) 
	{
        OutputError(table, func, err);
        goto Exit0;
    }
    result = true;
Exit0:
    EndScriptProfilerTimer();
    return result;
}

template<typename RETURN>
bool  LuaScript::CallTableFuncRetFromStack(const char* table, const char * func, RETURN & retValue, int beginStackIndex, int paramCount) 
{
    BeginScriptProfilerTimer(table, func);
    MMO_ASSERT(table);
    MMO_ASSERT(func);
    MMO_ASSERT(lua_state_);
    bool result = false;
    try 
	{
        int topIndex = lua_gettop(lua_state_);
        LuaRef ref = luabridge::getGlobal(lua_state_, table);
        MMOLOG_ASSERT_EXIT(ref.isTable());
        {
            LuaRef fun = ref[func];
            MMOLOG_ASSERT_EXIT(fun.isFunction());
            {
                fun.push(lua_state_);
                Stack<LuaRef>::push(lua_state_, ref);
                for (int i = 0; i < paramCount; ++i) 
				{
                    lua_pushvalue(lua_state_, beginStackIndex + i);
                }
                luabridge::LuaException::pcall(lua_state_, paramCount + 1, 1);
                LuaRef ret = LuaRef::fromStack(lua_state_, topIndex + 1);
                retValue = ret.cast<RETURN>();
            }
        }
    }
    catch (luabridge::LuaException& err) 
	{
        OutputError(table, func, err);
        goto Exit0;
    }
    result = true;
Exit0:
    EndScriptProfilerTimer();
    return result;
}
